/*
 * Copyright 2023-2025, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * 龙芯LoongArch64架构设备树支持
 * 本文件实现LoongArch64架构的设备树解析和处理功能
 */

#include <KernelExport.h>

#include <arch/cpu.h>
#include <boot/kernel_args.h>
#include <device_manager.h>
#include <kernel.h>
#include <vm/vm.h>

// 定义调试输出宏
#define TRACE_FDT
#ifdef TRACE_FDT
#define TRACE(x...) dprintf("fdt_support: " x)
#else
#define TRACE(x...) ;
#endif

// FDT头部结构
struct fdt_header {
	uint32 magic;
	uint32 totalsize;
	uint32 off_dt_struct;
	uint32 off_dt_strings;
	uint32 off_mem_rsvmap;
	uint32 version;
	uint32 last_comp_version;
	uint32 boot_cpuid_phys;
	uint32 size_dt_strings;
	uint32 size_dt_struct;
};

// FDT魔数
#define FDT_MAGIC 0xd00dfeed

// FDT节点类型
#define FDT_BEGIN_NODE 0x1
#define FDT_END_NODE   0x2
#define FDT_PROP       0x3
#define FDT_NOP        0x4
#define FDT_END        0x9

// 全局变量
static void* sFdt = NULL;
static struct fdt_header* sFdtHeader = NULL;

// 字节序转换函数
static inline uint32 fdt32_to_cpu(uint32 value)
{
	return B_BENDIAN_TO_HOST_INT32(value);
}

// 验证FDT头部
static bool
validate_fdt_header(struct fdt_header* header)
{
	if (fdt32_to_cpu(header->magic) != FDT_MAGIC) {
		TRACE("Invalid FDT magic: %#08x\n", fdt32_to_cpu(header->magic));
		return false;
	}

	TRACE("FDT version: %d, size: %d bytes\n", 
		fdt32_to_cpu(header->version), fdt32_to_cpu(header->totalsize));
	return true;
}

// 初始化FDT支持
status_t
fdt_support_init(kernel_args* args)
{
	TRACE("Initializing FDT support\n");

	// 获取FDT指针
	sFdt = (void*)args->arch_args.fdt.Get();
	if (sFdt == NULL) {
		TRACE("No FDT found in kernel args\n");
		return B_ERROR;
	}

	// 验证FDT头部
	sFdtHeader = (struct fdt_header*)sFdt;
	if (!validate_fdt_header(sFdtHeader)) {
		TRACE("Invalid FDT header\n");
		return B_ERROR;
	}

	TRACE("FDT found at %p\n", sFdt);
	return B_OK;
}

// 查找节点路径对应的偏移量
static int
fdt_path_offset_internal(const void* fdt, const char* path)
{
	if (fdt == NULL || path == NULL)
		return -1;

	// 获取FDT结构和字符串块的偏移量
	const struct fdt_header* header = (const struct fdt_header*)fdt;
	uint32 struct_offset = fdt32_to_cpu(header->off_dt_struct);
	uint32 strings_offset = fdt32_to_cpu(header->off_dt_strings);
	uint32 struct_size = fdt32_to_cpu(header->size_dt_struct);

	// 从根节点开始查找
	int offset = struct_offset;
	int depth = 0;
	const char* p = path;

	// 跳过开头的斜杠
	if (*p == '/')
		p++;

	// 遍历路径的每个组件
	while (*p != '\0') {
		// 跳过连续的斜杠
		while (*p == '/')
			p++;

		if (*p == '\0')
			break;

		// 获取当前路径组件
		const char* component = p;
		int component_len = 0;
		while (*p != '/' && *p != '\0') {
			p++;
			component_len++;
		}

		// 在当前节点中查找子节点
		bool found = false;
		while (offset < struct_offset + struct_size) {
			uint32 tag = fdt32_to_cpu(*(uint32*)(((char*)fdt) + offset));
			offset += sizeof(uint32);

			switch (tag) {
			case FDT_BEGIN_NODE: {
				const char* name = ((char*)fdt) + offset;
				int name_len = 0;
				while (name[name_len] != '\0')
					name_len++;

				// 对齐到4字节边界
				offset += (name_len + 1 + 3) & ~3;

				// 检查是否匹配当前路径组件
				if (depth == 0) {
					// 根节点特殊处理
					depth++;
					found = true;
					break;
				} else if (name_len == component_len && 
					   strncmp(name, component, component_len) == 0) {
					depth++;
					found = true;
					break;
				}
				depth++;
				break;
			}
			case FDT_END_NODE:
				depth--;
				if (depth < 0)
					return -1; // 错误：节点结构不匹配
				break;
			case FDT_PROP: {
				uint32 len = fdt32_to_cpu(*(uint32*)(((char*)fdt) + offset));
				offset += sizeof(uint32) + sizeof(uint32); // 跳过len和nameoff
				offset += (len + 3) & ~3; // 对齐到4字节边界
				break;
			}
			case FDT_NOP:
				break;
			case FDT_END:
				return -1; // 到达FDT结尾，未找到节点
			default:
				return -1; // 未知标签
			}

			if (found)
				break;
		}

		if (!found)
			return -1; // 未找到子节点
	}

	return offset;
}

// 获取FDT属性
static const void*
fdt_get_property(const char* nodepath, const char* name, int* lenp)
{
	if (sFdt == NULL || nodepath == NULL || name == NULL) {
		if (lenp)
			*lenp = -1;
		return NULL;
	}

	// 查找节点偏移量
	int offset = fdt_path_offset_internal(sFdt, nodepath);
	if (offset < 0) {
		TRACE("Node not found: %s\n", nodepath);
		if (lenp)
			*lenp = -1;
		return NULL;
	}

	// 获取FDT结构和字符串块的偏移量
	uint32 struct_offset = fdt32_to_cpu(sFdtHeader->off_dt_struct);
	uint32 strings_offset = fdt32_to_cpu(sFdtHeader->off_dt_strings);
	uint32 struct_size = fdt32_to_cpu(sFdtHeader->size_dt_struct);

	// 在节点中查找属性
	while (offset < struct_offset + struct_size) {
		uint32 tag = fdt32_to_cpu(*(uint32*)(((char*)sFdt) + offset));
		offset += sizeof(uint32);

		switch (tag) {
		case FDT_PROP: {
			uint32 len = fdt32_to_cpu(*(uint32*)(((char*)sFdt) + offset));
			offset += sizeof(uint32);
			uint32 nameoff = fdt32_to_cpu(*(uint32*)(((char*)sFdt) + offset));
			offset += sizeof(uint32);

			// 获取属性名称
			const char* prop_name = (const char*)sFdt + strings_offset + nameoff;
			
			// 检查属性名称是否匹配
			if (strcmp(prop_name, name) == 0) {
				// 找到匹配的属性
				if (lenp)
					*lenp = len;
				return (const void*)(((char*)sFdt) + offset);
			}

			// 跳过属性值，对齐到4字节边界
			offset += (len + 3) & ~3;
			break;
		}
		case FDT_BEGIN_NODE: {
			// 跳过节点名称，对齐到4字节边界
			const char* name = ((char*)sFdt) + offset;
			int name_len = 0;
			while (name[name_len] != '\0')
				name_len++;
			offset += (name_len + 1 + 3) & ~3;
			break;
		}
		case FDT_END_NODE:
			// 到达节点结尾，未找到属性
			if (lenp)
				*lenp = -1;
			return NULL;
		case FDT_NOP:
			break;
		case FDT_END:
			// 到达FDT结尾，未找到属性
			if (lenp)
				*lenp = -1;
			return NULL;
		default:
			// 未知标签
			if (lenp)
				*lenp = -1;
			return NULL;
		}
	}

	// 未找到属性
	if (lenp)
		*lenp = -1;
	return NULL;
}

// 查找中断控制器节点
status_t
fdt_find_interrupt_controller(addr_t* extioi_addr, addr_t* liointc_addr, addr_t* pch_pic_addr)
{
	TRACE("Finding LoongArch64 interrupt controllers\n");
	
	if (extioi_addr == NULL || liointc_addr == NULL || pch_pic_addr == NULL) {
		TRACE("Invalid parameters\n");
		return B_BAD_VALUE;
	}
	
	// 初始化为0，表示未找到
	*extioi_addr = 0;
	*liointc_addr = 0;
	*pch_pic_addr = 0;
	
	// 查找龙芯EXTIOI中断控制器
	int len;
	const uint32* reg;
	
	// 查找EXTIOI节点
	reg = (const uint32*)fdt_get_property("/soc/extioi", "reg", &len);
	if (reg != NULL && len >= 8) {
		// 获取EXTIOI控制器的物理地址
		*extioi_addr = fdt32_to_cpu(reg[0]);
		TRACE("Found EXTIOI controller at %#" B_PRIxADDR "\n", *extioi_addr);
	} else {
		// 尝试其他可能的路径
		reg = (const uint32*)fdt_get_property("/loongson/extioi", "reg", &len);
		if (reg != NULL && len >= 8) {
			*extioi_addr = fdt32_to_cpu(reg[0]);
			TRACE("Found EXTIOI controller at %#" B_PRIxADDR "\n", *extioi_addr);
		}
	}
	
	// 查找LIOINTC节点
	reg = (const uint32*)fdt_get_property("/soc/liointc", "reg", &len);
	if (reg != NULL && len >= 8) {
		// 获取LIOINTC控制器的物理地址
		*liointc_addr = fdt32_to_cpu(reg[0]);
		TRACE("Found LIOINTC controller at %#" B_PRIxADDR "\n", *liointc_addr);
	} else {
		// 尝试其他可能的路径
		reg = (const uint32*)fdt_get_property("/loongson/liointc", "reg", &len);
		if (reg != NULL && len >= 8) {
			*liointc_addr = fdt32_to_cpu(reg[0]);
			TRACE("Found LIOINTC controller at %#" B_PRIxADDR "\n", *liointc_addr);
		}
	}
	
	// 查找PCH_PIC节点
	reg = (const uint32*)fdt_get_property("/soc/pch-pic", "reg", &len);
	if (reg != NULL && len >= 8) {
		// 获取PCH_PIC控制器的物理地址
		*pch_pic_addr = fdt32_to_cpu(reg[0]);
		TRACE("Found PCH_PIC controller at %#" B_PRIxADDR "\n", *pch_pic_addr);
	} else {
		// 尝试其他可能的路径
		reg = (const uint32*)fdt_get_property("/loongson/pch-pic", "reg", &len);
		if (reg != NULL && len >= 8) {
			*pch_pic_addr = fdt32_to_cpu(reg[0]);
			TRACE("Found PCH_PIC controller at %#" B_PRIxADDR "\n", *pch_pic_addr);
		}
	}
	
	// 检查是否至少找到一个中断控制器
	if (*extioi_addr == 0 && *liointc_addr == 0 && *pch_pic_addr == 0) {
		TRACE("No interrupt controllers found\n");
		return B_ERROR;
	}
	
	TRACE("Successfully found interrupt controllers\n");
	return B_OK;
}

// 查找定时器节点
status_t
fdt_find_timer(addr_t* timer_addr, uint32* timer_freq)
{
	TRACE("Finding LoongArch64 timer\n");
	
	if (timer_addr == NULL || timer_freq == NULL) {
		TRACE("Invalid parameters\n");
		return B_BAD_VALUE;
	}
	
	// 初始化为0，表示未找到
	*timer_addr = 0;
	*timer_freq = 0;
	
	// 查找龙芯定时器
	int len;
	const uint32* reg;
	const uint32* freq;
	
	// 尝试查找/soc/timer节点
	reg = (const uint32*)fdt_get_property("/soc/timer", "reg", &len);
	if (reg != NULL && len >= 8) {
		// 获取定时器的物理地址
		*timer_addr = fdt32_to_cpu(reg[0]);
		TRACE("Found timer at %#" B_PRIxADDR "\n", *timer_addr);
		
		// 尝试获取定时器频率
		freq = (const uint32*)fdt_get_property("/soc/timer", "clock-frequency", &len);
		if (freq != NULL && len >= 4) {
			*timer_freq = fdt32_to_cpu(freq[0]);
			TRACE("Timer frequency: %lu Hz\n", *timer_freq);
		} else {
			// 如果没有找到clock-frequency属性，尝试查找timebase-frequency属性
			freq = (const uint32*)fdt_get_property("/soc/timer", "timebase-frequency", &len);
			if (freq != NULL && len >= 4) {
				*timer_freq = fdt32_to_cpu(freq[0]);
				TRACE("Timer frequency (timebase): %lu Hz\n", *timer_freq);
			}
		}
	} else {
		// 尝试其他可能的路径
		reg = (const uint32*)fdt_get_property("/loongson/timer", "reg", &len);
		if (reg != NULL && len >= 8) {
			*timer_addr = fdt32_to_cpu(reg[0]);
			TRACE("Found timer at %#" B_PRIxADDR "\n", *timer_addr);
			
			// 尝试获取定时器频率
			freq = (const uint32*)fdt_get_property("/loongson/timer", "clock-frequency", &len);
			if (freq != NULL && len >= 4) {
				*timer_freq = fdt32_to_cpu(freq[0]);
				TRACE("Timer frequency: %lu Hz\n", *timer_freq);
			} else {
				// 如果没有找到clock-frequency属性，尝试查找timebase-frequency属性
				freq = (const uint32*)fdt_get_property("/loongson/timer", "timebase-frequency", &len);
				if (freq != NULL && len >= 4) {
					*timer_freq = fdt32_to_cpu(freq[0]);
					TRACE("Timer frequency (timebase): %lu Hz\n", *timer_freq);
				}
			}
		}
	}
	
	// 如果没有找到定时器地址，尝试查找RTC节点
	if (*timer_addr == 0) {
		reg = (const uint32*)fdt_get_property("/soc/rtc", "reg", &len);
		if (reg != NULL && len >= 8) {
			*timer_addr = fdt32_to_cpu(reg[0]);
			TRACE("Found RTC at %#" B_PRIxADDR "\n", *timer_addr);
		} else {
			reg = (const uint32*)fdt_get_property("/loongson/rtc", "reg", &len);
			if (reg != NULL && len >= 8) {
				*timer_addr = fdt32_to_cpu(reg[0]);
				TRACE("Found RTC at %#" B_PRIxADDR "\n", *timer_addr);
			}
		}
	}
	
	// 如果没有找到频率，使用默认值
	if (*timer_freq == 0) {
		// 龙芯3A5000/3A6000默认定时器频率为100MHz
		*timer_freq = 100000000;
		TRACE("Using default timer frequency: %lu Hz\n", *timer_freq);
	}
	
	// 检查是否找到定时器
	if (*timer_addr == 0) {
		TRACE("No timer found\n");
		return B_ERROR;
	}
	
	TRACE("Successfully found timer\n");
	return B_OK;
}

// 解析内存节点
status_t
fdt_parse_memory(kernel_args* args)
{
	TRACE("Parsing memory nodes from device tree\n");
	
	if (sFdt == NULL) {
		TRACE("No FDT available\n");
		return B_ERROR;
	}
	
	// 查找memory节点
	int memoryNode = fdt_path_offset_internal(sFdt, "/memory");
	if (memoryNode < 0) {
		// 尝试其他可能的路径
		memoryNode = fdt_path_offset_internal(sFdt, "/memory@0");
	}
	
	if (memoryNode < 0) {
		TRACE("No memory node found in device tree\n");
		return B_ERROR;
	}
	
	// 获取reg属性，包含内存范围信息
	int len;
	const uint32* reg = (const uint32*)fdt_get_property("/memory", "reg", &len);
	if (reg == NULL) {
		// 尝试其他可能的路径
		reg = (const uint32*)fdt_get_property("/memory@0", "reg", &len);
	}
	
	if (reg == NULL || len < 8) {
		TRACE("No valid memory ranges found\n");
		return B_ERROR;
	}
	
	// 获取地址和大小单元格数量
	// 默认值：地址使用2个单元格，大小使用1个单元格
	uint32 addressCells = 2;
	uint32 sizeCells = 1;
	
	// 尝试从根节点获取#address-cells和#size-cells属性
	int rootNode = fdt_path_offset_internal(sFdt, "/");
	if (rootNode >= 0) {
		const uint32* prop;
		int propLen;
		
		prop = (const uint32*)fdt_get_property("/", "#address-cells", &propLen);
		if (prop != NULL && propLen >= 4)
			addressCells = fdt32_to_cpu(*prop);
		
		prop = (const uint32*)fdt_get_property("/", "#size-cells", &propLen);
		if (prop != NULL && propLen >= 4)
			sizeCells = fdt32_to_cpu(*prop);
	}
	
	TRACE("Memory node: address-cells=%lu, size-cells=%lu\n", addressCells, sizeCells);
	
	// 解析内存范围
	uint32 entrySize = 4 * (addressCells + sizeCells);
	uint32 numEntries = len / entrySize;
	
	if (numEntries == 0) {
		TRACE("No memory ranges found\n");
		return B_ERROR;
	}
	
	TRACE("Found %lu memory range(s)\n", numEntries);
	
	// 遍历所有内存范围
	for (uint32 i = 0; i < numEntries; i++) {
		uint64 start = 0;
		uint64 size = 0;
		
		// 解析起始地址
		switch (addressCells) {
			case 1:
				start = fdt32_to_cpu(reg[i * (addressCells + sizeCells)]);
				break;
			case 2:
				start = fdt32_to_cpu(reg[i * (addressCells + sizeCells)]);
				start = (start << 32) | fdt32_to_cpu(reg[i * (addressCells + sizeCells) + 1]);
				break;
			default:
				TRACE("Unsupported address-cells: %lu\n", addressCells);
				continue;
		}
		
		// 解析大小
		switch (sizeCells) {
			case 1:
				size = fdt32_to_cpu(reg[i * (addressCells + sizeCells) + addressCells]);
				break;
			case 2:
				size = fdt32_to_cpu(reg[i * (addressCells + sizeCells) + addressCells]);
				size = (size << 32) | fdt32_to_cpu(reg[i * (addressCells + sizeCells) + addressCells + 1]);
				break;
			default:
				TRACE("Unsupported size-cells: %lu\n", sizeCells);
				continue;
		}
		
		TRACE("Memory range %lu: start=%#" B_PRIx64 ", size=%#" B_PRIx64 " (%" B_PRIu64 " MB)\n", 
			i, start, size, size / (1024 * 1024));
		
		// 添加到物理内存范围列表
		if (start > 0 && size > 0) {
			status_t status = insert_address_range(args->physical_memory_range,
				&args->num_physical_memory_ranges, MAX_PHYSICAL_MEMORY_RANGE,
				start, size);
			
			if (status != B_OK) {
				TRACE("Failed to insert memory range: %s\n", strerror(status));
			}
		}
	}
	
	// 处理保留内存区域
	// 获取/reserved-memory节点
	int reservedNode = fdt_path_offset_internal(sFdt, "/reserved-memory");
	if (reservedNode >= 0) {
		TRACE("Processing reserved memory regions\n");
		
		// 遍历/reserved-memory的子节点
		int childNode = -1;
		int depth = 0;
		
		// 获取FDT结构和字符串块的偏移量
		uint32 struct_offset = fdt32_to_cpu(sFdtHeader->off_dt_struct);
		uint32 struct_size = fdt32_to_cpu(sFdtHeader->size_dt_struct);
		
		// 从reserved-memory节点开始遍历
		uint32 offset = reservedNode;
		
		while (offset < struct_offset + struct_size) {
			uint32 tag = fdt32_to_cpu(*(uint32*)(((char*)sFdt) + offset));
			offset += sizeof(uint32);
			
			switch (tag) {
			case FDT_BEGIN_NODE: {
				const char* name = ((char*)sFdt) + offset;
				int name_len = 0;
				while (name[name_len] != '\0')
					name_len++;
				
				// 对齐到4字节边界
				offset += (name_len + 1 + 3) & ~3;
				
				depth++;
				if (depth == 1) {
					// 这是reserved-memory节点本身，跳过
					break;
				}
				
				// 处理reserved-memory的子节点
				TRACE("Found reserved memory node: %s\n", name);
				break;
			}
			case FDT_END_NODE:
				depth--;
				if (depth < 0) {
					// 已经处理完reserved-memory节点
					goto done_reserved;
				}
				break;
			case FDT_PROP: {
				uint32 len = fdt32_to_cpu(*(uint32*)(((char*)sFdt) + offset));
				offset += sizeof(uint32);
				uint32 nameoff = fdt32_to_cpu(*(uint32*)(((char*)sFdt) + offset));
				offset += sizeof(uint32);
				
				// 如果是reg属性且在子节点中，处理保留内存范围
				if (depth > 1) {
					const char* prop_name = (const char*)sFdt + 
						fdt32_to_cpu(sFdtHeader->off_dt_strings) + nameoff;
					
					if (strcmp(prop_name, "reg") == 0) {
						// 解析保留内存范围
						const uint32* resReg = (const uint32*)(((char*)sFdt) + offset);
						
						uint64 resStart = 0;
						uint64 resSize = 0;
						
						// 解析起始地址
						switch (addressCells) {
							case 1:
								resStart = fdt32_to_cpu(resReg[0]);
								break;
							case 2:
								resStart = fdt32_to_cpu(resReg[0]);
								resStart = (resStart << 32) | fdt32_to_cpu(resReg[1]);
								break;
						}
						
						// 解析大小
						switch (sizeCells) {
							case 1:
								resSize = fdt32_to_cpu(resReg[addressCells]);
								break;
							case 2:
								resSize = fdt32_to_cpu(resReg[addressCells]);
								resSize = (resSize << 32) | fdt32_to_cpu(resReg[addressCells + 1]);
								break;
						}
						
						TRACE("Reserved memory: start=%#" B_PRIx64 ", size=%#" B_PRIx64 "\n", 
							resStart, resSize);
						
						// 从物理内存范围中移除保留区域
						if (resStart > 0 && resSize > 0) {
							status_t status = remove_address_range(args->physical_memory_range,
								&args->num_physical_memory_ranges, MAX_PHYSICAL_MEMORY_RANGE,
								resStart, resSize);
							
							if (status != B_OK) {
								TRACE("Failed to remove reserved memory range: %s\n", strerror(status));
							}
						}
					}
				}
				
				// 跳过属性值，对齐到4字节边界
				offset += (len + 3) & ~3;
				break;
			}
			case FDT_NOP:
				break;
			case FDT_END:
				goto done_reserved;
			default:
				TRACE("Unknown FDT tag: %#x\n", tag);
				break;
			}
		}
	}

	done_reserved:
	// 检查是否成功解析了内存范围
	if (args->num_physical_memory_ranges == 0) {
		TRACE("No physical memory ranges were added\n");
		return B_ERROR;
	}
	
	TRACE("Successfully parsed %lu physical memory ranges\n", args->num_physical_memory_ranges);
	return B_OK;
}